﻿ #include "appmonitortask.h"
#include "QProcess"

#include "AppMonitorTaskManager.h"
#include "dbservice.h"

AppMonitorTask::AppMonitorTask(const AppMonitor & appMonitor):appMonitor(appMonitor)
{
    appRunningState= AppRunningState_unknown;
}

AppMonitorTask::~AppMonitorTask()
{

}

void AppMonitorTask::changeAppRunningState(AppRunningState state)
{
    if(appRunningState != state)
    {
        appRunningState = state;
        emit gAppMonitorTaskManager.taskChanged();
    }

}

int AppMonitorTask::start()
{

    if(state == RunableStateStoping)
    {
        LOG_ERROR("task with id:%ld, name:%s, type:%d is not appMonitor.started in db, can't start this thread", appMonitor.id, QStr2CStr(appMonitor.name), appMonitor.type);
        return f_success;
    }

    changeAppRunningState(AppRunningState_unknown);
    while(state == RunableStateStarted)
    {

        if(isAppRunning())
        {
            if(isMemOverLoad())
            {
                LOG_INFO("task with id:%ld, name:%s, type:%d's memory overload, stop it by force and  sleep:%d seconds and check again",appMonitor.id, QStr2CStr(appMonitor.name), appMonitor.type, appMonitor.checkIntervalSeconds);


                QString returnInfo("");
                sendAppMonitorRestartLogAndSaveToDb(AppMonitorLog(appMonitor.name, QString(APP_MONITOR_LOG_ACTION_KILL_WHEN_MEM_OVERLOAD), sayTime(QDateTime::currentDateTime())), returnInfo);
                changeAppRunningState(AppRunningState_stopping);
                stopAppByForce();
                changeAppRunningState(AppRunningState_stopped);

            }
            else
            {
                changeAppRunningState(AppRunningState_running);
                LOG_INFO("task with id:%ld, name:%s, type:%d is running, will sleep:%d seconds and check again",appMonitor.id, QStr2CStr(appMonitor.name), appMonitor.type, appMonitor.checkIntervalSeconds);
            }


            for(int i = 0; i < appMonitor.checkIntervalSeconds; i++)
            {
                if(state == RunableStateStoping) break;
                Sleep(1000);
            }

            if(state == RunableStateStoping)
            {
                LOG_INFO("task with id:%ld, name:%s, type:%d changed to not appMonitor.started, will end this monitor task",appMonitor.id, QStr2CStr(appMonitor.name), appMonitor.type);
                break;
            }
        }
        else
        {

            startApp();

            QString returnInfo("");
            sendAppMonitorRestartLogAndSaveToDb(AppMonitorLog(appMonitor.name, QString(APP_MONITOR_LOG_ACTION_RESTART), sayTime(QDateTime::currentDateTime())), returnInfo);

            Sleep(1000);
            for(int i = 0; i < appMonitor.checkIntervalSeconds; i++)
            {
                if(state == RunableStateStoping)
                {
                    break;
                }
                else
                {
                   if(!isAppRunning())
                   {
                       Sleep(1000);
                   }
                   else
                   {
                       break;
                   }
                }
            }
        }
    }
    return f_success;
}

void AppMonitorTask::stopAppByForce()
{
    int pid = getPid();

    if(pid > 0)
    {
        killAppByPID(pid);
    }
    else
    {
        LOG_ERROR("try to get pid failed, can't stop app");
    }
}

int AppMonitorTask::getPid()
{
    int pid = -1;
    if(appMonitor.type == MonitorType_listenSocket)
    {
        int port = atoi(QStr2CStr(appMonitor.cfgInfo));
        if(port > 0)
        {
            pid = getPidByListenPort(port);
        }

    }
    else if (appMonitor.type == MonitorType_appName)
    {
        pid = getPidByAppName(appMonitor.cfgInfo);
    }


    return pid;
}

void AppMonitorTask::startApp()
{
    changeAppRunningState(AppRunningState_starting);
    //            QProcess qProcess;
    //            qProcess.start(appMonitor.startCmd);
    execCmdWithOutResult(appMonitor.startCmd);
    //            gDBService.saveOneAppMonitorLog(AppMonitorLog(appMonitor.name, QString(APP_MONITOR_LOG_ACTION_RESTART), sayTime(QDateTime::currentDateTime())));
    //            emit gAppMonitorTaskManager.appRestarted();
}

bool AppMonitorTask::  isAppRunning()
{
    if(appMonitor.type == MonitorType_listenSocket)
    {
        int port = atoi(QStr2CStr(appMonitor.cfgInfo));
        if(port < 0)
        {
            LOG_ERROR("port invalid, cfg info:%s need to be a port", QStr2CStr(appMonitor.cfgInfo));
            return true;
        }
        else
        {
            return isSocketOnListenning(port);
        }
    }
    else if(appMonitor.type == MonitorType_appName)
    {
        QString appName = appMonitor.cfgInfo;
        return isAppNameRunning(appName);
    }

    return true;
}

bool AppMonitorTask::isMemOverLoad()
{
    bool ret = false;

    if(appMonitor.maxMemLimitKB > 0)
    {
        int pid = getPid();
        if(pid >= 0)
        {
            int memUsdKB = getMemoryUsageKBByPid(pid);
            if(memUsdKB > appMonitor.maxMemLimitKB)
            {
                LOG_INFO("appMonitor:%s, memused kb:%d >  threshold:%d, over laod", QStr2CStr(appMonitor.name), memUsdKB, appMonitor.maxMemLimitKB);
                ret = true;
            }
        }
    }

    return ret;
}


QString AppMonitorTask::sayState()
{

    QString ret;

    if(state == RunableStateStoped)
    {
       return ret = "监控未启动";
    }
    else if(state == RunableStateStoping)
    {
        return ret = "正在停止监控";
    }
    else
    {
        if(appRunningState == AppRunningState_unknown)
        {
            return ret = "正在检测应用运行状态";
        }
        else if(appRunningState == AppRunningState_starting)
        {
            return ret = "正在启动应用程序";
        }
        else if(appRunningState == AppRunningState_running)
        {
            return ret = "应用运行中";
        }
        else if(appRunningState == AppRunningState_stopping)
        {
            return ret = "停止应用中";
        }
        else if(appRunningState == AppRunningState_stopped)
        {
            return ret = "应用已停止运行";
        }
    }

    return ret = "未知错误";
}

AppRunningInfo AppMonitorTask::getCurrentRunningInfo()
{
    AppRunningInfo ret;
    ret.name = appMonitor.name.toStdString();
    ret.cfgInfo = appMonitor.cfgInfo.toStdString();
    ret.startCmd = appMonitor.startCmd.toStdString();
    ret.type = appMonitor.getTypeName().toStdString();
    ret.runningState = sayState().toStdString();

    return ret;
}
